/*
 * Copyright 2019 Flipkart Internet Pvt. Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.flipkart.ohos.proteus.recyclerview.v7;

import com.flipkart.ohos.proteus.ProteusBuilder;
import com.flipkart.ohos.proteus.recyclerview.v7.adapter.ListContainerProviderFactory;
import com.flipkart.ohos.proteus.recyclerview.v7.adapter.ProteusListContainerProvider;
import com.flipkart.ohos.proteus.recyclerview.v7.adapter.SimpleListProvider;
import com.flipkart.ohos.proteus.recyclerview.v7.layoutmanager.LayoutManagerBuilder;
import com.flipkart.ohos.proteus.recyclerview.v7.layoutmanager.LayoutManagerFactory;
import com.flipkart.ohos.proteus.recyclerview.v7.layoutmanager.ProteusDirectionalLayoutManager;
import com.flipkart.ohos.proteus.recyclerview.v7.widget.ListContainerParser;

/**
 * <p>
 * RecyclerView Module contains the attribute processors, Layout Manager and Adapter Factories, and
 * their default implementations for the {@link ohos.agp.components.ListContainer}.
 * </p>
 *
 * @author adityasharat
 * @see ListContainerProviderFactory
 * @see LayoutManagerFactory
 */
public class ListContainerModule implements ProteusBuilder.Module {
    static final String ADAPTER_SIMPLE_LIST = "SimpleListProvider";

    static final String LAYOUT_MANAGER_LINEAR = "DirectionalLayoutManager";

    private final ListContainerProviderFactory adapterFactory;

    private final LayoutManagerFactory layoutManagerFactory;

    /**
     * <p>
     * Returns a new instance of the Recycler View Module.
     * </p>
     *
     * @param adapterFactory The adapter factory to be used to evaluate the
     * {@link ListContainerParser#ATTRIBUTE_ADAPTER} attribute.
     * @param layoutManagerFactory The layout manager factory to evaluate the
     * {@link ListContainerParser#ATTRIBUTE_LAYOUT_MANAGER} attribute.
     */
    ListContainerModule(ListContainerProviderFactory adapterFactory, LayoutManagerFactory layoutManagerFactory) {
        this.adapterFactory = adapterFactory;
        this.layoutManagerFactory = layoutManagerFactory;
    }

    /**
     * <p>
     * The default constructor method to create a new instance of this class. This method internally
     * uses the {@link Builder} and registers the default Adapters and Layout Managers of the
     * Recycler View.
     * </p>
     *
     * @return Returns a new instance of the module with default implementations registered.
     * @see SimpleListProvider
     * @see ProteusDirectionalLayoutManager
     */
    public static ListContainerModule create() {
        return new Builder().build();
    }

    @Override
    public void registerWith(ProteusBuilder builder) {
        builder.register(new ListContainerParser(adapterFactory, layoutManagerFactory));
    }

    /**
     * Use the Recycler View Module Builder to register custom {@link ProteusListContainerProvider}
     * implementations. A default {@link ProteusListContainerProvider} and
     * {@link ohos.agp.components.ListContainer} are included by default. To
     * exclude them call {@link #excludeDefaultAdapters()} and {@link #excludeDefaultLayoutManagers()}.
     *
     * @author adityasharat
     * @see ProteusListContainerProvider
     * @see ListContainerProviderFactory
     * @see SimpleListProvider
     * @see LayoutManagerFactory
     * @see ProteusDirectionalLayoutManager
     */
    @SuppressWarnings("WeakerAccess")
    public static class Builder {
        private final ListContainerProviderFactory adapterFactory = new ListContainerProviderFactory();

        private LayoutManagerFactory layoutManagerFactory = new LayoutManagerFactory();

        private boolean includeDefaultAdapters = true;

        private boolean includeDefaultLayoutManagers = true;

        /**
         * <p>
         * Registers a new {@link ProteusListContainerProvider}.
         * </p>
         *
         * @param type The 'type' of the adapter which will be used in the {@link ListContainerParser#ATTRIBUTE_ADAPTER}
         * attribute.
         * @param builder The builder for the adapter.
         * @return this builder.
         */
        public Builder register(String type, ProteusListContainerProvider.Builder builder) {
            adapterFactory.register(type, builder);
            return this;
        }

        /**
         * <p>
         * Registers a new {@link ProteusListContainerProvider}.
         * </p>
         *
         * @param type The {@link ListContainerParser#ATTRIBUTE_TYPE} of the layout manager which will be used in the
         * {@link ListContainerParser#ATTRIBUTE_LAYOUT_MANAGER} attribute.
         * @param builder The builder for the layout manager.
         * @return this builder.
         */
        public Builder register(String type, LayoutManagerBuilder builder) {
            layoutManagerFactory.register(type, builder);
            return this;
        }

        /**
         * <p>
         * Will exclude the default {@link ProteusListContainerProvider} implementations from the module.
         * </p>
         *
         * @return this builder.
         */
        public Builder excludeDefaultAdapters() {
            includeDefaultAdapters = false;
            return this;
        }

        /**
         * <p>
         * Will exclude the default
         * implementations from the module.
         * </p>
         *
         * @return this builder.
         */
        public Builder excludeDefaultLayoutManagers() {
            includeDefaultLayoutManagers = false;
            return this;
        }

        /**
         * <p>
         * Returns a new instance of {@link ListContainerModule}.
         * </p>
         *
         * @return a new instance of {@link ListContainerModule}.
         */
        public ListContainerModule build() {
            if (includeDefaultAdapters) {
                registerDefaultAdapters();
            }

            if (includeDefaultLayoutManagers) {
                registerDefaultLayoutManagers();
            }
            return new ListContainerModule(adapterFactory, layoutManagerFactory);
        }

        private void registerDefaultAdapters() {
            register(ADAPTER_SIMPLE_LIST, SimpleListProvider.BUILDER);
        }

        private void registerDefaultLayoutManagers() {
            register(LAYOUT_MANAGER_LINEAR, ProteusDirectionalLayoutManager.BUILDER);
        }
    }
}
